#include <signal.h>
#include <unistd.h>
#include <errno.h>

#include <cstdio>
#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>

#include "server.h"

using namespace crawler::server;

namespace {
std::string GetHelp() {
  std::ostringstream oss;
  oss << "usage: fetcherd options" << std::endl
      << "Start fetcher server." << std::endl
      << "options:  -s path      storage database path" << std::endl
      << "          -p port      server port" << std::endl
      << "          -H homepage  fetching homepage";
  return oss.str();
}
Server *g_server = NULL;
void SignalHandler(int sig) {
  static bool called = false;

  // execute handler.
  if (!called && g_server != NULL) {
    std::cout << "SignalHandler received signal " << sig
              << ", stopping the server" << std::endl;
    g_server->Stop();
    called = true;
  }
}
void InitSignals(Server *server) {
  // mask all signals except SIGTERM and SIGINT
  sigset_t mask;
  sigfillset(&mask);
  sigdelset(&mask, SIGTERM);
  sigdelset(&mask, SIGINT);
  int ret = sigprocmask(SIG_SETMASK, &mask, 0);
  if (ret == -1) {
    throw std::runtime_error(std::string("sigprocmask failed, ") + strerror(errno));
  }

  // set signal handler, the handler will be executed only once(SA_RESETHAND).
  g_server = server;
  struct sigaction act;
  act.sa_handler = SignalHandler;
  sigfillset(&act.sa_mask);
  //act.sa_flags = SA_RESETHAND;
  ret = sigaction(SIGTERM, &act, 0);
  if (ret == -1) {
    throw std::runtime_error(std::string("sigaction failed, ") + strerror(errno));
  }
  ret = sigaction(SIGINT, &act, 0);
  if (ret == -1) {
    throw std::runtime_error(std::string("sigaction failed, ") + strerror(errno));
  }
}
}

int main(int argc, char **argv)
{
  try {
    Config config(argc, argv);
    if (config.need_help()) {
      std::cout << GetHelp() << std::endl;
      return EXIT_SUCCESS;
    }

    Server server(&config);
    InitSignals(&server);

    server.Start();
    server.Join();
  } catch (const std::exception &ex) {
    std::cerr << ex.what() << std::endl;
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

